home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
machserver
/
1.098
/
sched
/
schedQueue.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-24
|
9KB
|
312 lines
/*
* schedQueue.c --
*
* Routines for ordering processes in the run queue based on weighted
* usage.
*
* Copyright 1985 Regents of the University of California
* All rights reserved.
*/
#ifndef lint
static char rcsid[] = "$Header: /sprite/src/kernel/sched/RCS/schedQueue.c,v 9.3 90/10/05 17:14:29 mendel Exp $ SPRITE (Berkeley)";
#endif /* not lint */
#include <sprite.h>
#include <mach.h>
#include <proc.h>
#include <list.h>
#include <sync.h>
#include <sched.h>
#include <schedInt.h>
List_Links schedReadyQueueHeader;
List_Links *schedReadyQueueHdrPtr = &schedReadyQueueHeader;
Sched_OnDeck sched_OnDeck[MACH_MAX_NUM_PROCESSORS];
int sched_Insert;
int sched_QueueEmpty;
int sched_Stage;
int sched_Preempt;
/*
* ----------------------------------------------------------------------------
*
* Sched_SetClearUsageFlag --
*
* Set flag in process table entry for the current process that says to
* clear usage info whenever is scheduled.
*
* Results:
* None.
*
* Side effects:
* schedFlags field modified for calling process.
*
* ----------------------------------------------------------------------------
*/
void
Sched_SetClearUsageFlag()
{
Proc_ControlBlock *procPtr;
procPtr = Proc_GetCurrentProc();
MASTER_LOCK(sched_MutexPtr);
procPtr->schedFlags |= SCHED_CLEAR_USAGE;
MASTER_UNLOCK(sched_MutexPtr);
}
/*
* ----------------------------------------------------------------------------
*
* Sched_InsertInQueue --
*
* Given a pointer to a process, move it in the run queue (or insert
* it if it is not already there) based on its current weighted usage.
* If the process is of higher priority than the current process,
* flag the current process as having a pending context switch.
*
* Results:
* None.
*
* Side effects:
* Process is moved within or added to the run queue. If the process
* is added, the global count of the number of ready processes is
* incremented.
*
* ----------------------------------------------------------------------------
*/
INTERNAL void
Sched_InsertInQueue(procPtr, runPtrPtr)
register Proc_ControlBlock *procPtr; /* pointer to process to
move/insert */
Proc_ControlBlock **runPtrPtr; /* returns process from
* front of queue.
*/
{
register Proc_ControlBlock *itemProcPtr;
register List_Links *queuePtr;
Boolean insert;
Boolean delete;
Boolean foundInsertPoint;
List_Links *followingItemPtr;
int i;
Proc_ControlBlock *lowestProcPtr;
int processor;
sched_Insert++;
if (procPtr->schedFlags & SCHED_CLEAR_USAGE) {
procPtr->recentUsage = 0;
procPtr->weightedUsage = 0;
procPtr->unweightedUsage = 0;
}
processor = procPtr->processor;
queuePtr = schedReadyQueueHdrPtr;
if (mach_NumProcessors > 1) {
if (sched_ProcessorStatus[processor] ==
SCHED_PROCESSOR_COUNTING_TICKS) {
if (sched_OnDeck[processor].procPtr != (Proc_ControlBlock *) NIL) {
panic("Count of ticks screwed up.");
}
sched_OnDeck[processor].procPtr = procPtr;
if (runPtrPtr != (Proc_ControlBlock **) NIL) {
*runPtrPtr = (Proc_ControlBlock *) NIL;
}
return;
} else if (List_IsEmpty(queuePtr)) {
/*
* Special case an empty queue. If the queue is empty there may be
* idle processors. We optimize things by bypassing the queue and
* giving processes to the processors through the staging areas.
*/
sched_QueueEmpty++;
/*
* If we are supposed to return a runnable process and the process
* we were given last ran on the current processor, then just return
* the process.
*/
if ((runPtrPtr != (Proc_ControlBlock **) NIL) &&
(processor == Mach_GetProcessorNumber())) {
*runPtrPtr = procPtr;
return;
}
/*
* If the last processor to run the process is idle then just give
* the process to that processor.
*/
if ((proc_RunningProcesses[processor] == (Proc_ControlBlock *) NIL) &&
(sched_ProcessorStatus[processor] == SCHED_PROCESSOR_ACTIVE)) {
if (sched_OnDeck[processor].procPtr ==
(Proc_ControlBlock *) NIL) {
sched_OnDeck[processor].procPtr = procPtr;
procPtr = (Proc_ControlBlock *) NIL;
/*
* There is already a process on deck, but the one new one
* can't be run by anyone else because it's stack is in
* use by this processor. Switch the two processes.
*/
} else if (procPtr->schedFlags & SCHED_STACK_IN_USE) {
Proc_ControlBlock *tempPtr;
tempPtr = procPtr;
procPtr = sched_OnDeck[processor].procPtr;
sched_OnDeck[processor].procPtr = tempPtr;
}
}
if (procPtr != (Proc_ControlBlock *) NIL &&
!(procPtr->schedFlags & SCHED_STACK_IN_USE)) {
/*
* Give the process to any idle processor. It's stack cannot
* be in use (it can't be run anyway so don't bother trying).
*/
for (i = 0; i < mach_NumProcessors; i++) {
if ((sched_ProcessorStatus[i] == SCHED_PROCESSOR_ACTIVE) &&
(proc_RunningProcesses[i] == (Proc_ControlBlock *) NIL) &&
(sched_OnDeck[i].procPtr ==
(Proc_ControlBlock *) NIL)) {
sched_OnDeck[i].procPtr = procPtr;
procPtr = (Proc_ControlBlock *) NIL;
break;
}
}
}
/*
* If we gave the process away then we're done.
*/
if (procPtr == (Proc_ControlBlock *) NIL) {
sched_Stage++;
if (runPtrPtr != (Proc_ControlBlock **) NIL) {
*runPtrPtr = (Proc_ControlBlock *) NIL;
}
return;
}
}
}
/*
* Compare the process's weighted usage to the usage of the currently
* running processes. If the new process has higher priority (lower
* usage) than one of the current processes, then force the current
* process to context switch.
* The context switch will occur in one of two places.
* 1) If we are being called at interrupt level, and the interrupt occurred
* in user mode, then the context switch will occur prior to returning
* to user mode. (the CallInterruptHandler macro checks the
* specialHandling flag)
* 2) The next time the current process enters a trap handler.
*
*/
lowestProcPtr = (Proc_ControlBlock *) NIL;
for (i = 0; i < mach_NumProcessors; i++) {
itemProcPtr = proc_RunningProcesses[i];
if (itemProcPtr == (Proc_ControlBlock *) NIL) {
continue;
}
if ((lowestProcPtr == (Proc_ControlBlock *) NIL) ||
(itemProcPtr->weightedUsage > lowestProcPtr->weightedUsage)) {
lowestProcPtr = itemProcPtr;
}
}
if ((lowestProcPtr != (Proc_ControlBlock *) NIL) &&
(procPtr->weightedUsage < lowestProcPtr->weightedUsage)) {
sched_Preempt++;
lowestProcPtr->schedFlags |= SCHED_CONTEXT_SWITCH_PENDING;
lowestProcPtr->specialHandling = 1;
}
if (List_IsEmpty(queuePtr)) {
/*
* This is easy if the queue is empty.
*/
if (runPtrPtr != (Proc_ControlBlock **) NIL) {
*runPtrPtr = procPtr;
return;
} else {
List_Insert((List_Links *) procPtr, LIST_ATREAR(queuePtr));
sched_Instrument.numReadyProcesses = 1;
return;
}
}
/*
* Loop through all elements in the run queue. Search for the first
* process with a weighted usage greater than the process being inserted.
*
* If a process is found that belongs after procPtr, set foundInsertPoint
* and just look for procPtr to see whether the process is being moved
* or inserted. If procPtr has already been found and the insert point
* has been determined, exit the loop.
*/
insert = TRUE;
delete = FALSE;
foundInsertPoint = FALSE;
itemProcPtr = (Proc_ControlBlock *) schedReadyQueueHdrPtr;
followingItemPtr = (List_Links *) NIL;
LIST_FORALL(queuePtr, (List_Links *) itemProcPtr) {
if (itemProcPtr == procPtr) {
delete = TRUE;
}
if (foundInsertPoint && delete) {
break;
}
if (foundInsertPoint) {
continue;
}
if (procPtr->weightedUsage < itemProcPtr->weightedUsage) {
followingItemPtr = (List_Links *) itemProcPtr;
if (((List_Links *)(procPtr))->nextPtr ==
(List_Links *) followingItemPtr && delete) {
insert = FALSE;
delete = FALSE;
break;
}
foundInsertPoint = TRUE;
}
}
if (foundInsertPoint) {
itemProcPtr = (Proc_ControlBlock *)LIST_BEFORE(followingItemPtr);
}
/*
* Process was already on queue in a different position so delete it.
*/
if (delete) {
List_Remove((List_Links *) procPtr);
sched_Instrument.numReadyProcesses -= 1;
}
if (runPtrPtr != (Proc_ControlBlock **) NIL) {
if (foundInsertPoint && (List_Links *)itemProcPtr == queuePtr) {
/*
* We are being inserted at the front
* of the queue so return ourselves.
*/
*runPtrPtr = procPtr;
return;
}
}
/*
* Insert the process into the queue.
*/
if (insert) {
if (foundInsertPoint) {
List_Insert((List_Links *) procPtr, (List_Links *) itemProcPtr);
} else {
List_Insert((List_Links *) procPtr, LIST_ATREAR(queuePtr));
}
sched_Instrument.numReadyProcesses += 1;
}
/*
* If we are to return a process then delete the first process from
* the queue.
*/
if (runPtrPtr != (Proc_ControlBlock **) NIL) {
Proc_ControlBlock *tempPtr;
tempPtr = (Proc_ControlBlock *)List_First(queuePtr);
List_Remove((List_Links *)tempPtr);
*runPtrPtr = tempPtr;
sched_Instrument.numReadyProcesses -= 1;
}
}